#include "test_utils.h"
#include <fstream>
#include <sstream>
#include <iostream>
#include <cstdlib>
#include <filesystem>
#include <chrono>
#include <thread>
#include <unistd.h>

namespace TestUtils {

BuildResult executeBuildCommand(const std::string& command, int timeoutSeconds) {
    BuildResult result;
    std::string outputFile = "test_output_" + std::to_string(std::time(nullptr)) + ".txt";
    
    // 保存当前目录
    std::filesystem::path currentDir = std::filesystem::current_path();
    
    // 切换到项目根目录 (从tests目录切换到上级目录)
    std::filesystem::path projectRoot;
    if (currentDir.filename() == "tests") {
        projectRoot = currentDir.parent_path();
    } else {
        projectRoot = currentDir; // 如果已经在根目录，保持不变
    }
    std::filesystem::current_path(projectRoot);
    
    // 确保BUILD_PROJECT_ROOT环境变量正确设置
    std::string projectRootStr = projectRoot.string();
    setenv("BUILD_PROJECT_ROOT", projectRootStr.c_str(), 1);
    
    // 构建完整命令
    std::string fullCommand = command + " > " + outputFile + " 2>&1";
    
    auto start = std::chrono::steady_clock::now();
    result.exitCode = system(fullCommand.c_str());
    auto end = std::chrono::steady_clock::now();
    
    result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    
    // 读取输出
    std::ifstream file(outputFile);
    if (file.is_open()) {
        std::stringstream buffer;
        buffer << file.rdbuf();
        result.output = buffer.str();
        file.close();
    }
    
    // 清理临时文件
    std::filesystem::remove(outputFile);
    
    // 恢复原目录
    std::filesystem::current_path(currentDir);
    
    return result;
}

bool fileExists(const std::string& path) {
    return std::filesystem::exists(path);
}

bool directoryExists(const std::string& path) {
    return std::filesystem::exists(path) && std::filesystem::is_directory(path);
}

std::string readFile(const std::string& path) {
    std::ifstream file(path);
    if (!file.is_open()) {
        return "";
    }
    
    std::stringstream buffer;
    buffer << file.rdbuf();
    return buffer.str();
}

bool containsString(const std::string& text, const std::string& substring) {
    return text.find(substring) != std::string::npos;
}

void cleanupBuildOutputs() {
    system("./build.sh -c > /dev/null 2>&1 || true");
    system("rm -f test_*.txt > /dev/null 2>&1 || true");
}

void setEnvironmentVariable(const std::string& name, const std::string& value) {
    setenv(name.c_str(), value.c_str(), 1);
}

void unsetEnvironmentVariable(const std::string& name) {
    unsetenv(name.c_str());
}

std::vector<std::string> findFiles(const std::string& directory, const std::string& pattern) {
    std::vector<std::string> files;
    
    if (!std::filesystem::exists(directory)) {
        return files;
    }
    
    for (const auto& entry : std::filesystem::recursive_directory_iterator(directory)) {
        if (entry.is_regular_file()) {
            std::string filename = entry.path().filename().string();
            if (filename.find(pattern) != std::string::npos) {
                files.push_back(entry.path().string());
            }
        }
    }
    
    return files;
}

bool waitForFile(const std::string& path, int timeoutSeconds) {
    auto start = std::chrono::steady_clock::now();
    auto timeout = std::chrono::seconds(timeoutSeconds);
    
    while (std::chrono::steady_clock::now() - start < timeout) {
        if (std::filesystem::exists(path)) {
            return true;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    
    return false;
}

TestScope::TestScope(const std::string& testName) : testName_(testName) {
    std::cout << "[TEST SCOPE] Starting: " << testName_ << std::endl;
    cleanupBuildOutputs();
}

TestScope::~TestScope() {
    cleanupBuildOutputs();
    std::cout << "[TEST SCOPE] Finished: " << testName_ << std::endl;
}

} // namespace TestUtils